﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;


namespace ctem.gui
{
    class ModelSaveLoader
    {
        Model model;
        ConfigManager config;

        public ActorTypeConfig FindByClassName(string ClassName, List<ActorTypeConfig> typeslist)
        {
            for (int i = 0; i < typeslist.Count; i++)
                if (typeslist[i].ClassName == ClassName) return typeslist[i];
            return null;
        }

        public ActorTypeConfig FindByVisibleName(string VisibleName, List<ActorTypeConfig> typeslist)
        {
            for (int i = 0; i < typeslist.Count; i++)
                if (typeslist[i].VisibleName == VisibleName) return typeslist[i];
            return null;
        }


        public void ClearModel()
        {
            List<GraphBuilder.Vertex> actors = model.vis_graph.GetAllVertex();
            foreach (GraphBuilder.Vertex actor in actors)
                model.modeller.AsyncSendCommand("del actor " + actor.Name);
            model.vis_graph.Clear();
            model.FileName = "";
            model.Name = "";
            //model.
        }

        public ModelSaveLoader(Model _model, ConfigManager config)
        {
            model = _model; this.config = config;
        }

        public void LoadModel(string file_name,ConfigManager config)
        {
            //ClearModel();
            XmlDocument model_xml = new XmlDocument();
            model_xml.Load(file_name);

            XmlNodeList list_of_actors = model_xml.GetElementsByTagName("actor");
            // бежим по всем акторам
            for (int i = 0; i < list_of_actors.Count; i++)
            {
                if (list_of_actors[i].Name == "actor")
                {
                    string actor_name = list_of_actors[i].Attributes["name"].Value.ToString();
                    string actor_class = list_of_actors[i].Attributes["class"].Value.ToString();
                    ActorTypeConfig loaded_actor = FindByClassName(actor_class, config.KnowActorTypes);
                    
                    //string param1 = config.MainFolder+"\\"+loaded_actor.Assembly;
                    //model.modeller.AsyncSendCommand("new actor" + " " + " '" + param1 + "' " + actor_class + " " + actor_name);
                    model.modeller.AsyncSendCommand("new actor" + " " + " '" + loaded_actor.Assembly + "' " + actor_class + " " + actor_name);

                    int x =0,y =0, width=0,height=0;
                    
                    XmlNodeList list_of_Children = list_of_actors[i].ChildNodes;

                    for (int k = 0; k < list_of_Children.Count; k++)
                    {
                        if (list_of_Children[k].Name == "params")
                        {
                            XmlNodeList list_of_params = list_of_Children[k].ChildNodes;
                            for (int m = 0; m < list_of_params.Count; m++)
                            {
                                if (list_of_params[m].Name == "param")
                                {
                                    string param_name = list_of_params[m].Attributes["name"].Value.ToString();
                                    if (loaded_actor.ClassName == "ctem.samples.actors.sequential.CommonW")
                                    {
                                        string param_val = list_of_params[m].InnerText;
                                        model.modeller.AsyncSendCommand("set param " + actor_name + "." + param_name + " " + param_val.ToString());
                                    }
                                    else
                                    {
                                        double param_val = System.Convert.ToDouble(list_of_params[m].InnerText);
                                        model.modeller.AsyncSendCommand("set param " + actor_name + "." + param_name + " " + param_val.ToString());
                                    }
                                }
                            }
                        }
                        else
                        if (list_of_Children[k].Name == "UI")
                        {
                            XmlNodeList list_of_UIElems = list_of_Children[k].ChildNodes;
                            for (int m = 0; m < list_of_UIElems.Count; m++)
                            {
                                if (list_of_UIElems[m].Name == "x") x = System.Convert.ToInt32(list_of_UIElems[m].InnerText);
                                else
                                    if (list_of_UIElems[m].Name == "y") y = System.Convert.ToInt32(list_of_UIElems[m].InnerText);
                                    else
                                        if (list_of_UIElems[m].Name == "width") width = System.Convert.ToInt32(list_of_UIElems[m].InnerText);
                                        else
                                            if (list_of_UIElems[m].Name == "height") height = System.Convert.ToInt32(list_of_UIElems[m].InnerText);
                            }
                        }
                    }
                    
                    GraphBuilder.Vertex item = new GraphBuilder.Vertex(new System.Drawing.Rectangle(x,y,width,height));
                    item.Name = actor_name;
                    item.ClassName = loaded_actor.ClassName;
                    item.VisibleName = loaded_actor.VisibleName;
                    List<string> inports = model.modeller.SyncSendCommand<List<string>>("get all inports " + actor_name);
                    foreach (string inp in inports)
                        model.vis_graph.AddElement(new GraphBuilder.Port(item, GraphBuilder.TPortType.In, inp));

                    List<string> outports = model.modeller.SyncSendCommand<List<string>>("get all outports " + actor_name);
                    foreach (string outp in outports)
                        model.vis_graph.AddElement(new GraphBuilder.Port(item, GraphBuilder.TPortType.Out, outp));

                    //item.bitmap = new System.Drawing.Bitmap(config.MainFolder+"\\"+loaded_actor.Icon);
                    item.bitmap = new System.Drawing.Bitmap(loaded_actor.Icon);
                    model.vis_graph.AddElement(item);
                }
            }

            XmlNodeList list_of_links = model_xml.GetElementsByTagName("link");
            for (int i = 0; i < list_of_links.Count; i++)
            {
                if (list_of_links[i].Name == "link")
                {
                    string fromName = "", toName = "";
                    XmlNodeList list_of_Children = list_of_links[i].ChildNodes;
                    for (int k = 0; k < list_of_Children.Count; k++)
                    {
                        if (list_of_Children[k].Name == "fromName") fromName = list_of_Children[k].InnerText;
                        else
                            if (list_of_Children[k].Name == "toName") toName = list_of_Children[k].InnerText;
                    }
                    model.modeller.AsyncSendCommand("new link" + " " + " " + fromName + " " + toName);
                    model.vis_graph.AddElement(new GraphBuilder.Edge(model.vis_graph.GetElementByName(fromName) as GraphBuilder.Port, model.vis_graph.GetElementByName(toName) as GraphBuilder.Port));
                }
            }
            model.FileName = file_name;
        }

        public void SaveModel(string file_name, ConfigManager config)
        {
            //if (!System.IO.File.Exists(file_name))
            //    System.IO.File.Create(file_name);
            XmlDocument model_xml = new XmlDocument();
            
            //model_xml.CreateElement("Model");
            model_xml.CreateXmlDeclaration("1.0", "UTF-8", "");
            XmlNode model_node = model_xml.CreateNode(XmlNodeType.Element,"model",null);
            XmlAttribute model_attr = model_xml.CreateAttribute("name");
            model_attr.InnerText = model.Name;
            model_node.Attributes.Append(model_attr);

            XmlNode actors_node = model_xml.CreateNode(XmlNodeType.Element,"actors",null);
            XmlNode links_node = model_xml.CreateNode(XmlNodeType.Element,"links",null);
            model_node.AppendChild(actors_node);
            model_node.AppendChild(links_node);

            List<GraphBuilder.Vertex> actors = model.vis_graph.GetAllVertex();
            foreach (GraphBuilder.Vertex actor in actors)
            {
                ActorTypeConfig saved_actor = FindByClassName(actor.ClassName, config.KnowActorTypes);
                XmlAttribute actor_attr1 = model_xml.CreateAttribute("name");
                actor_attr1.InnerText = actor.Name;
                XmlAttribute actor_attr2 = model_xml.CreateAttribute("class");
                actor_attr2.InnerText = actor.ClassName;

                XmlNode actor_node = model_xml.CreateNode(XmlNodeType.Element, "actor", null);
                actor_node.Attributes.Append(actor_attr1);
                actor_node.Attributes.Append(actor_attr2);
                actors_node.AppendChild(actor_node);

                XmlNode params_node = model_xml.CreateNode(XmlNodeType.Element, "params", null);
                actor_node.AppendChild(params_node);

                List<string> parameters = null;
                parameters = model.modeller.SyncSendCommand<List<string>>("get all params " + actor.Name);
                foreach (String par in parameters)
                {
                    XmlNode param_node = model_xml.CreateNode(XmlNodeType.Element, "param", null);
                    XmlAttribute param_name = model_xml.CreateAttribute("name");
                    param_name.InnerText = par;
                    param_node.Attributes.Append(param_name);

                    if (saved_actor.ClassName == "ctem.samples.actors.sequential.CommonW")
                        param_node.InnerText = model.modeller.SyncSendCommand<string>("get param value " + actor.Name + "." + par).ToString();
                    else
                        param_node.InnerText = model.modeller.SyncSendCommand<double>("get param value " + actor.Name + "." + par).ToString();

                    params_node.AppendChild(param_node);
                }

                XmlNode UI_node = model_xml.CreateNode(XmlNodeType.Element, "UI", null);
                actor_node.AppendChild(UI_node);

                XmlNode x_node = model_xml.CreateNode(XmlNodeType.Element, "x", null);
                x_node.InnerText = actor.GetLeftCenter().X.ToString();
                UI_node.AppendChild(x_node);
                XmlNode y_node = model_xml.CreateNode(XmlNodeType.Element, "y", null);
                y_node.InnerText = actor.GetTopCenter().Y.ToString();
                UI_node.AppendChild(y_node);
                XmlNode width_node = model_xml.CreateNode(XmlNodeType.Element, "width", null);
                width_node.InnerText = actor.Rect.Width.ToString();
                UI_node.AppendChild(width_node);
                XmlNode height_node = model_xml.CreateNode(XmlNodeType.Element, "height", null);
                height_node.InnerText = actor.Rect.Height.ToString();
                UI_node.AppendChild(height_node);
                //actor_node.Attributes
            }

            List<GraphBuilder.Edge> links = model.vis_graph.GetAllEdges();
            foreach (GraphBuilder.Edge link in links)
            {
                XmlNode link_node = model_xml.CreateNode(XmlNodeType.Element, "link", null);
                links_node.AppendChild(link_node);

                XmlNode from_node = model_xml.CreateNode(XmlNodeType.Element, "fromName", null);
                from_node.InnerText = link.fromPort.Name;
                link_node.AppendChild(from_node);

                XmlNode to_node = model_xml.CreateNode(XmlNodeType.Element, "toName", null);
                to_node.InnerText = link.toPort.Name;
                link_node.AppendChild(to_node);
            }
            //new_node.Attributes.;
            model_xml.AppendChild(model_node);
            //model_xml.DocumentElement.AppendChild(new_node);
            model_xml.Save(file_name);
            model.FileName = file_name;
        }

    }
}
